/**************************************************************************************
 *
 * @(#) JwtAuthenticationFilter.java
 * @Package com.jgdt.jgdtkasannong_university_gene_backend.config
 **************************************************************************************/
package com.jgdt.jgdtkasannong_university_gene_backend.config.filter;

import com.jgdt.jgdtkasannong_university_gene_backend.common.Sysconstant;
import com.jgdt.jgdtkasannong_university_gene_backend.common.enums.SystemCodeEnums;
import com.jgdt.jgdtkasannong_university_gene_backend.common.example.custom.BusinessException;
import com.jgdt.jgdtkasannong_university_gene_backend.utils.JwtUtils;
import com.jgdt.jgdtkasannong_university_gene_backend.utils.RedisUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
/**
 * @description: Jwt 认证过滤器扩展
 * @author: huangAn
 * @createDate: 2025/04/18
 */
@Component
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final UserDetailsService userDetailsService;

    @Autowired
    private JwtUtils jwtUtils1;
    @Autowired
    private RedisUtils redisUtils;


    // 构造器注入（推荐）
    @Autowired
    public JwtAuthenticationFilter(JwtUtils jwtUtils, UserDetailsService userDetailsService) {
        this.jwtUtils1 = jwtUtils;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain
    ) throws ServletException, IOException {

        try {
            // 1. 从请求头中获取 JWT Token
            String token = getJwtFromRequest(request);
            // 2. 验证 Token 的有效性
            if (StringUtils.hasText(token) && jwtUtils1.validateToken(token)) {
                // 3. 从 Token 中解析用户名
                String username = jwtUtils1.getUsernameFromToken(token);
                //登出黑名单拦截：
                if(redisUtils.hasKey(Sysconstant.USER_LOGIN_BLACKLIST_KEY_USERNAME +username)){
                        throw new BusinessException(SystemCodeEnums.UNAUTHORIZED.getKey(),SystemCodeEnums.UNAUTHORIZED.getMsg());
                }
                // 4. 根据用户名加载用户信息
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                // 5. 创建 Authentication 对象并设置到 SecurityContext
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails,
                        null,
                        userDetails.getAuthorities()
                );
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception e) {
            // Token 无效或过期时，清理 SecurityContext
            SecurityContextHolder.clearContext();
            log.warn("doFilterInternal Token 处理 warn:"+e.getMessage());
        }
        // 6. 继续执行后续过滤器链
        filterChain.doFilter(request, response);
    }

    /**
     * 从请求头中提取 Token
     * @param request
     * @return
     */
    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        boolean hasBool=StringUtils.hasText(bearerToken);
        boolean withBool=bearerToken.startsWith("Bearer ");
        if (hasBool && withBool) {
            return bearerToken.substring(7);
        }
        return null;
    }
}





